package com.demo.api.config;


import com.demo.api.cache.UrlCache;
import com.demo.api.controller.BaseController;
import com.demo.api.service.logs.ISysLogService;
import com.demo.core.enums.ErrorEnum;
import com.demo.core.exception.CustomException;
import com.demo.core.exception.ServerException;
import com.demo.core.response.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;


import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import java.util.*;

/**
 * @author Tan-Bowen
 * @description TODO 统一异常处理
 * @date 2021/8/4 19:05
 */
@Slf4j
@ControllerAdvice
public class ExceptionHandler extends BaseController {

    @Resource
    private ISysLogService logService;

    @Resource
    private UrlCache urlCache;

    @org.springframework.web.bind.annotation.ExceptionHandler(ServerException.class)
    @ResponseBody
    public ApiResponse<ErrorEnum> handleServerException(HttpServletRequest request, ServerException e) {
        //log.error("ServerException code:{},msg:{}",e.getErrorEnum().getCode(),e.getErrorEnum().getMsg());
        log.error("{}", e);
        logService.createErrorLog(request, e.getErrorEnum(),e.getMessage());
        return ApiResponse.error(e);
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(CustomException.class)
    @ResponseBody
    public ApiResponse<ErrorEnum> handleCustomException(HttpServletRequest request, CustomException e) {
        return ApiResponse.paramError(e.getMsg());
    }

    /**
     * 方法参数校验
     */
    @ResponseBody
    @org.springframework.web.bind.annotation.ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResponse<ErrorEnum> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        //log.error("{}", e.getMessage());
        log.error("{}", e);
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();

        for (ObjectError error : allErrors) {
            log.error(error.getDefaultMessage());
        }
        return ApiResponse.paramError(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
    }

    /**
     * ValidationException
     */
//    @ResponseBody
//    @org.springframework.web.bind.annotation.ExceptionHandler(ValidationException.class)
//    public ApiResponse<ErrorEnum> handleValidationException(ValidationException e) {
//        //log.error("{}", e.getMessage());
//        log.error("{}", e);
//        return ApiResponse.paramError(e.getCause().getMessage());
//    }

    /**
     * ConstraintViolationException
     */
    @ResponseBody
    @org.springframework.web.bind.annotation.ExceptionHandler(ConstraintViolationException.class)
    public ApiResponse<ErrorEnum> handleConstraintViolationException(ConstraintViolationException e) {
        StringBuilder sb = new StringBuilder();
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> item : violations) {
            sb.append(item.getMessage()).append(",");
            /** 打印验证不通过的信息 */
            log.error(item.getMessage());
        }
        sb.deleteCharAt(sb.length() - 1);
        return ApiResponse.paramError(sb.toString());
    }

    @ResponseBody
    @org.springframework.web.bind.annotation.ExceptionHandler(BindException.class)
    public ApiResponse<ErrorEnum> handleBindException(BindException e) {
        List<ObjectError> allErrors = e.getAllErrors();
        for (ObjectError error : allErrors) {
            log.error(error.getDefaultMessage());
        }
        return ApiResponse.paramError(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(Exception.class)
    @ResponseBody
    public ApiResponse<ErrorEnum> handleException(HttpServletRequest request, Exception e) {
        log.error("Exception：{}", e);
        return ApiResponse.error(ErrorEnum.SERVER_ERROR);
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(Throwable.class)
    @ResponseBody
    public ApiResponse<ErrorEnum> handleThrowable(HttpServletRequest request, Throwable e) {
        log.error("Throwable：{}", e);
        return ApiResponse.error(ErrorEnum.SERVER_ERROR);
    }


}
